package com.zhangmeng.service.impl;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.zhangmeng.handler.HandlerApi;
import com.zhangmeng.service.*;
import com.zhangmeng.utils.ByteBufferUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import org.apache.tomcat.util.http.fileupload.IOUtils;

import java.io.*;
import java.net.InetAddress;
import java.net.Socket;

/**
 * @author zm
 * @date 2025/2/22 11:41
 * @version: 1.0
 */
public class ConnectionImpl implements Connection {

    private final Log log = LogFactory.get();

    //当前连接的socket TCP套接字
    private Socket Conn;
    //当前连接的ID 也可以称作为SessionID，ID全局唯一
    private int ConnID;
    //当前连接的关闭状态
    private boolean isClosed;

    //该连接的处理方法api
    private HandlerApi handleAPI;

    //告知该链接已经退出/停止的channel
    boolean ExitBuffChan;

    //该连接的处理方法router
//    private Router router;
    private MsgHandle msgHandler;

    private BufferedReader reader;
    private BufferedWriter writer;
    private OutputStream outputStream;
    private InputStream inputStream;

    //当前Conn属于哪个Server
    private Server TcpServer;    //当前conn属于哪个server，在conn初始化的时候添加即可


    //创建连接的方法
    public ConnectionImpl(Server tcpServer,Socket conn, int connID, MsgHandle msgHandler) {
        this.Conn = conn;
        this.ConnID = connID;
        this.isClosed = false;
//        this.handleAPI = callback_api;
        this.ExitBuffChan = false;
//        this.router = router;
        this.msgHandler = msgHandler;

        try {
            this.inputStream = conn.getInputStream();
            this.outputStream = conn.getOutputStream();
            this.reader = new BufferedReader(new InputStreamReader(inputStream));
//            this.reader = new BufferedReader(new InputStreamReader(System.in));
            this.writer = new BufferedWriter(new OutputStreamWriter(outputStream));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        this.TcpServer = tcpServer;
        //将新创建的Conn添加到链接管理中
        this.TcpServer.GetConnMgr().Add(this);   //将当前新创建的连接添加到ConnManager中
    }

    public void close() {
        try {
            reader.close();
            writer.close();
            outputStream.close();
            inputStream.close();

            //将链接从连接管理器中删除
            this.TcpServer.GetConnMgr().Remove(this);  //删除conn从ConnManager中

            Conn.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    //直接将Message数据发送数据给远程的TCP客户端
    @Override
    public void SendMsg(int msgId, byte[] data) {
        if (this.isClosed) {
            throw new RuntimeException("Connection closed when send msg");
        }
        //将data封包，并且发送
        DataPack dp = new DataPackImpl();

        Message message = new MessageImpl();
        message.SetMsgId(msgId);
        message.SetData(data);
        message.SetDataLen(data.length);

        byte[] msg = dp.Pack(message);

        //写回客户端
        try {
            this.Conn.getOutputStream().write(msg);
        } catch (IOException e) {
//            throw new RuntimeException(e);
            close();
        }
    }

    //处理conn读数据的Goroutine
    public void StartReader() {
        log.info("Reader Goroutine is  running");
        boolean exit = true;
        while (exit) {
            //读取我们最大的数据到buf中
            try {

                //调用当前链接业务(这里执行的是当前conn的绑定的handle方法)
//                this.handleAPI.handle(this.writer, str.getBytes());

                //创建解析包对象
                DataPack dp = new DataPackImpl();

                ByteBuf inData = ByteBufferUtil.getByteBuf(inputStream, -1);

                //拆包，得到msgid 和 datalen 放在msg中
                byte[] data;
                Message unpack = dp.Unpack(inData);

                //构建request对象,并调用router的PreHandle,Handle,PostHandle方法
                Request request = new RequestImpl(this, unpack);

//                this.router.PreHandle(request);
//                this.router.Handle(request);
//                this.router.PostHandle(request);

                this.msgHandler.DoMsgHandler(request);

//                log.info("recv buf : " + str);
//                writer.write("\n");
//                writer.flush();
                ByteBufferUtil.sendMsg(3, "\n".getBytes(), outputStream);

            } catch (IOException e) {
//                throw new RuntimeException(e);
                log.error("recv buf err ", e.getMessage());
                //退出循环
                exit = false;
                this.ExitBuffChan = true;
                this.Stop();
            }
        }

    }


    @Override
    public void Start() {

        //==================
        //按照用户传递进来的创建连接时需要处理的业务，执行钩子方法
        this.TcpServer.CallOnConnStart(this);
        //==================

        log.info("Start ConnectionImpl ..............................................");
        StartReader();

    }

    @Override
    public void Stop() {
        log.info("Stop ConnectionImpl ..............................................");

        //==================
        //如果用户注册了该链接的关闭回调业务，那么在此刻应该显示调用
        this.TcpServer.CallOnConnStop(this);
        //==================

        //将链接从连接管理器中删除
        this.TcpServer.GetConnMgr().Remove(this);  //删除conn从ConnManager中

        //关闭当前连接
        this.close();
    }

    @Override
    public Socket GetTCPConnection() {
        return this.Conn;
    }

    @Override
    public int GetConnID() {
        return this.ConnID;
    }

    @Override
    public InetAddress RemoteAddr() {
        return this.Conn.getInetAddress();
    }


    public Socket getConn() {
        return Conn;
    }

    public void setConn(Socket conn) {
        Conn = conn;
    }

    public int getConnID() {
        return ConnID;
    }

    public void setConnID(int connID) {
        ConnID = connID;
    }

    public boolean isClosed() {
        return isClosed;
    }

    public void setClosed(boolean closed) {
        isClosed = closed;
    }

    public HandlerApi getHandleAPI() {
        return handleAPI;
    }

    public void setHandleAPI(HandlerApi handleAPI) {
        this.handleAPI = handleAPI;
    }

    public boolean isExitBuffChan() {
        return ExitBuffChan;
    }

    public void setExitBuffChan(boolean exitBuffChan) {
        ExitBuffChan = exitBuffChan;
    }

    public MsgHandle getMsgHandler() {
        return msgHandler;
    }

    public void setMsgHandler(MsgHandle msgHandler) {
        this.msgHandler = msgHandler;
    }
}
